//////////////////////////////////////////////////////////////////////////
//
// Globant Cpp Training 1
//
// Inheritance and Polymorphism
//
//////////////////////////////////////////////////////////////////////////

#include <iostream>
///////////////////////////////////////////////////////////////////////////
// Question: What is the output of the program?
/*
struct A { 
    virtual int foo(int x = 5) { 
        return x * 2; 
    } 
}; 

struct B : public A { 
    int foo(int x = 10) { 
        return x * 3; 
    } 
}; 

int main() { 
    A* a = new B; 
    std::cout << a->foo() << std::endl; 
}*/
// Answer: 15
// Description: The method B::foo is called but with the default argument of 5 
// from A::foo. "A virtual function call uses the default arguments in the 
// declaration of the virtual function determined by the static type of the 
// pointer or reference denoting the object. An overriding function in a 
// derived class does not acquire default arguments from the function it overrides."
//////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////
// Question: What is the output of the program?
/*
struct Foo {
    Foo() {} 

    void go() {
        std::cout << "Foo" << std::endl;
    }
};

struct Bar : public Foo {
    Bar() {}

    void go() {
        std::cout << "Bar" << std::endl;
    }
};

int main() { 
    Bar b;
    const Foo f = b;
    f.go();
}*/
// Answer: ill-formed
// Description: Non-const member functions can not be called on const objects.
//////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////
// Question: What is the output of the program?
/*
struct BS {
    unsigned int color;
};

struct car : public BS { };

struct truck : public BS { };

struct city : public car, public truck { };

int main() { 
    city c;
    c.color = 3;
    std::cout << c.color << std::endl;

    return 0; 
}*/
// Answer: ill-formed
// Description: The non-static members of a base class, that is an indirect 
// or direct base class more than once, can not be referred to without qualification.
//////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////
// Question: How many times is Hello World printed by this program?
/*
struct BS {
    BS() {
        std::cout << "Hello World" << std::endl;
    }
    unsigned int color;
};

struct mid1 : virtual public BS { };
struct mid2 : virtual public BS { };
struct mid3 : public BS { };
struct mid4 : public BS { };

struct DR : public mid1, public mid2, 
            public mid3, public mid4 { };

int main() { 
    DR d; 
}*/
// Answer: 3
// Description: One time for the first virtual occurrences of BS 
// in the hierarchy and once for each non-virtual occurrence of BS. 
// mid1 and mid2 together have one. mid3 and mid4 each have one.
//////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////
// Question: How many times is Hello World printed by this program?
/*
struct Shape {
    void print() {
        std::cout << "SHAPE" << std::endl;
    }
};

struct Box : public Shape {
    void print() {
        std::cout << "BOX" << std::endl;
    }
};

int main(int argc, char** argv) {
    Shape* s1 = new Box;
    s1->print();
}*/
// Answer: SHAPE
// Description: Shape::print is not a virtual function. 
// Therefore Shape::print is called even though s1 points to a Box object. 
// If print was virtual, then BOX would be printed.
//////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////
// Question: What gets printed by this program?
/*
struct Shape {
    virtual void print() {
        std::cout << "SHAPE" << std::endl;
    }
    virtual ~Shape() {}
};

struct Box : public virtual Shape {
    void print() {
        std::cout << "BOX" << std::endl;
    }
};

struct Sphere : public virtual Shape {
    void print() {
        std::cout << "SPHERE" << std::endl;
    }
};

struct GeoDisc : public Box, public Sphere { };

int main() {
    Shape* s = new GeoDisc;
    s->print();
    delete s;
}*/
// Answer: Ill-formed
// Description: Virtual functions must have a unique "final overrider" 
// that overrides all other instances of that function in its inheritance hierarchy.
// In this case neither Box::print nor Sphere::print override each other, 
// so the condition is not met and the GeoDisc class is ill-formed.
//////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////
// Question: How many times is Hello World printed by this program?
/*
struct BS {
    BS() {
        std::cout << "Hello World" << std::endl;
    }
};

struct mid1 : public BS { };
struct mid2 : public BS { };
struct mid3 : public BS { };
struct mid4 : public BS { };

struct DR : public virtual mid1, public virtual mid2, 
            public virtual mid3, public mid4 { };

int main() { 
    DR d; 
}*/
// Answer: 4
// Description: Virtual inheritance affects the class that is inherited virtually. 
// Therefore the BS base class is not inherited virtually and there are 4 
// of them within 1 DR object. The virtual inheritance statements in this 
// code are affecting the classes mid1, mid2, mid3, mid4 and not BS.
//////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////
// Question: What gets printed by this program?
/*
struct Shape {
    virtual void print() {
        std::cout << "SHAPE" << std::endl;
    }

    virtual ~Shape() {}
};

struct Box : public Shape {
    virtual void print(int i) {
        std::cout << "BOX" << std::endl;
    }
};

int main() { 
    Shape* s = new Box;
    s->print();
    delete s; 
}*/
// Answer: SHAPE
// Description:  A function with a different signature does not override 
// a function in a base class even if the function name is the same.
//////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////
// Question: What gets printed by this program?
/*
struct Shape {
    virtual Shape* duplicate() {
        std::cout << "SHAPE" << std::endl;
        return new Shape;
    }

    virtual ~Shape() {}
};

struct Box : public Shape {
    virtual Box* duplicate() {
        std::cout << "BOX" << std::endl;
        return new Box;
    }
};

int main() { 
    Shape* s1 = new Box;
    Shape* s2 = s1->duplicate();
    delete s1;
    delete s2;
}*/
// Answer: BOX
// Description: The return type of an overriding virtual function must have 
// either the same type as the function it is overriding or both functions 
// must return a pointer or reference with the same cv-qualifications whereby 
// the class pointed or reffered to in the overridden function is an unambiguous 
// and accessible direct or indirect base class of the class pointed or referred 
// to in the overriding function.
//////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////
// Question: What gets printed by this program?
/*
struct Shape {
    virtual Shape* duplicate() {
        return new Shape;
    }
    virtual void print() {
        std::cout << "SHAPE" << std::endl;
    }
    virtual ~Shape() {}
};

struct Box : public Shape {
    virtual Box* duplicate() {
        return new Box;
    }
    virtual void print() {
        std::cout << "BOX" << std::endl;
    }
};

int main() { 
    Shape* s1 = new Box;
    Box* b1 = s1->duplicate();
    b1->print();
    delete s1;
    delete b1;
}*/
// Answer: Ill-formed
// Description: The return type of the virtual function that is called 
// dynamically is converted to the return type of the overridden function. 
// In this case the result of the duplicate() function is a pointer to a Box 
// object but converted to a Shape pointer. Therefore the assignment from the 
// return value to b1 is ill-formed.
//////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////
// Question: What gets printed by this program?
/*
struct Shape {
    virtual void print(){
        std::cout << "SHAPE" << std::endl;
    }
    virtual ~Shape() {}
};

struct Box : private Shape {
    virtual void print() {
        std::cout << "BOX" << std::endl;
    }
};

int main() { 
    Shape* s = new Box;
    s->print();
    delete s; 
}*/
// Answer: Ill-formed
// Description: An implicit conversion from a pointer to a derived class, 
// to a pointer to an inaccessible (private inheritance) base class is ill-formed. 
// Thus the assignment of the new Box to Shape* is ill-formed.
//////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////
// Question: Which lines below should not compile?
/*
class Bar {
protected:
    static int x;
    int y;
 };

int  Bar::x = 33;

class Barrel : public Bar {
public:
    void foo(Bar* b, Barrel* d) {
        b->y = 0;
        d->y = 0;
        Bar::x = 0;
        Barrel::x = 0;
    }
};
int main() {
  Barrel b;
  b.foo(&b, &b);
}*/
// Answer: b->y = 0;
// Description: An implicit conversion from a pointer to a derived class, 
// to a pointer to an inaccessible (private inheritance) base class is ill-formed. 
// Thus the assignment of the new Box to Shape* is ill-formed.
//////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////
// Question: Which lines below should not compile?
/*
struct A {
    A(int x) : n(x) {}
    int n;
};

int main() {
    A a1;
    A a2(2);
    A a3(a2);
}*/
// Answer: A a1;
// Description: If any user-declared constructor is present in the class, 
// then no default constructor will be created implicitly. 
// Additionally if no user declared copy constructor is declared, 
// then an implicit copy constructor will be created by the compiler. 
// In this example there is a user-declared constructor which prevents 
// the default constructor from existing, but a copy constructor is still 
// created implicitly.
//////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////
// Question: What gets printed?
struct Car {
    Car() : price(20000) {}
    Car(double b) : price(b*1.1) {}
    double price;
};

struct Toyota : public virtual Car {
    Toyota(double b) : Car(b) {}
};

struct Prius : public Toyota {
    Prius(double b) : Toyota(b)  {}
};

int main() {
    Prius p(30000);
    std::cout << p.price << std::endl;
}
// Answer: 22000
// Description: All sub-objects representing virtual base classes are initialized 
// by the constructor of the most derived class. 
// If the constructor of the most derived class does not specify a member-initializer 
// for a virtual base class V, then V's default constructor is called to initialize 
// the virtual base class sub-object.
//////////////////////////////////////////////////////////////////////////
